package com.huxiaoshou.exam.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huxiaoshou.exam.entity.Category;
import com.huxiaoshou.exam.entity.Question;
import com.huxiaoshou.exam.mapper.CategoryMapper;
import com.huxiaoshou.exam.mapper.QuestionMapper;
import com.huxiaoshou.exam.service.CategoryService;
import com.huxiaoshou.exam.service.QuestionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {

    @Autowired
    private QuestionService questionService;

    @Autowired
    private QuestionMapper questionMapper;

    @Override
    public List<Category> getAllCategories() {
        List<Category> categoryList = this.lambdaQuery()
                .orderByAsc(Category::getSort)
                .list();

        fillQuestionCount(categoryList);
        return categoryList;
    }

    @Override
    public List<Category> getCategoryTree() {
        List<Category> categoryList = this.lambdaQuery()
                .orderByAsc(Category::getSort)
                .list();

        fillQuestionCount(categoryList);
        List<Category> buildTree = buildTree(categoryList);

        log.info("查询类别树状结构集合：{}", buildTree);
        return buildTree;
    }

    @Override
    public void addCategory(Category category) {
        Long count = this.lambdaQuery()
                .eq(Category::getParentId, category.getParentId())
                .eq(Category::getName, category.getName())
                .count();

        if (count > 0) {
            Category parent = getById(category.getParentId());
            // 不能添加，同一个父类下名称重复了
            throw new RuntimeException("在%s父分类下，已经存在名为：%s的子分类，本次添加失败！".formatted(parent.getName(), category.getName()));
        }

        this.save(category);
    }

    @Override
    public void updateCategory(Category category) {
        boolean exists = this.lambdaQuery()
                .eq(Category::getParentId, category.getParentId())
                .ne(Category::getId, category.getId())
                .eq(Category::getName, category.getName())
                .exists();

        if (exists) {
            Category parent = getById(category.getParentId());
            // 不能添加，同一个父类下名称重复了
            throw new RuntimeException("在%s父分类下，已经存在名为：%s的子分类，本次更新失败！".formatted(parent.getName(), category.getName()));
        }

        this.updateById(category);
    }

    @Override
    public void deleteCategory(Long id) {
        // 检查是否一级标题
        Category category = this.getById(id);
        if (category.getParentId() == 0) {
            throw new RuntimeException("不能删除一级标题！");
        }

        // 检查是否存在关联的题目
        Long count = questionService.lambdaQuery()
                .eq(Question::getCategoryId, id)
                .count();

        if (count > 0) {
            throw new RuntimeException("当前的:%s分类，关联了%s道题目,无法删除！".formatted(category.getName(), count));
        }

        // 以上不都不满足，删除即可【子关联数据，一并删除】
        this.removeById(id);
    }

    private List<Category> buildTree(List<Category> categoryList) {
        Map<Long, List<Category>> childrenMap = categoryList.stream()
                .collect(Collectors.groupingBy(Category::getParentId));

        categoryList.forEach(category -> {
            List<Category> children = childrenMap.getOrDefault(category.getId(), new ArrayList<>());
            category.setChildren(children);

            long childrenQuestionCount = children.stream()
                    .mapToLong(c -> c.getCount() != null ? c.getCount() : 0L)
                    .sum();

            long selfQuestionCount = category.getCount() != null ? category.getCount() : 0L;
            category.setCount(selfQuestionCount + childrenQuestionCount);
        });

        return categoryList.stream()
                .filter(c -> c.getParentId() == 0)
                .collect(Collectors.toList());
    }

    private void fillQuestionCount(List<Category> categoryList) {
        List<Map<Long, Object>> questionCountList = questionMapper.getCategoryQuestionCount();

        Map<Long, Long> questionCountMap = questionCountList.stream().collect(Collectors.toMap(
                map -> Long.valueOf(map.get("category_id").toString()),
                map -> Long.valueOf(map.get("count").toString())
        ));

        categoryList.forEach(category -> {
            category.setCount(questionCountMap.getOrDefault(category.getId(), 0L));
        });
    }

}